package com.example.multithread.completablefuture;

import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StopWatch;

import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

/**
 * @ClassName CompletableFutureDemo2
 * @Description TODO
 * @Author leejiliang
 * @DateTime 2020/5/25 3:12 PM
 * @Version 1.0
 */
@Slf4j
public class CompletableFutureDemo4 {
	static Random random = new Random();


	public static void main(String[] arg) {
		//五个运动员列表
		List<Athlete> athletes = List.of(
				new Athlete("jacky"),
				new Athlete("lucy"),
				new Athlete("tony"),
				new Athlete("tom"),
				new Athlete("perter"));
		StopWatch stopWatch = new StopWatch();
//		stopWatch.start("以同步的方式开始测试");
//		List<String> result = runSync(athletes);

//		stopWatch.start("以并行流的方式开始测试");
//		List<String> result = runAsyncWithParallel(athletes);

//		stopWatch.start("用 CompletableFuture的方式开始测试");
//		List<String> result = runAsyncWithCF(athletes);

		ExecutorService executorService = Executors.newFixedThreadPool(5, r -> {
			Thread t1 = new Thread(r);
			t1.setDaemon(true);
			return t1;
		});

//		ExecutorService executorService1 = Executors.newFixedThreadPool(30);
		stopWatch.start("用自定义线程池的方式使用 CompletableFuture 开始测试");
//		List<String> result = runAsyncWithCombine(athletes, executorService);
		List<String> result = runAsyncWithCombine(athletes, executorService);

		stopWatch.stop();
		log.info(stopWatch.getTotalTimeSeconds() + "s");
		log.info(stopWatch.prettyPrint());
		result.forEach(log::info);


	}

	static List<String> runSync(List<Athlete> athletes) {
		return athletes.stream().map(CompletableFutureDemo4::runTest).map(CompletableFutureDemo4::runTestTwo).collect(Collectors.toList());
	}

	static List<String> runAsyncWithParallel(List<Athlete> athletes) {
		return athletes.parallelStream().map(CompletableFutureDemo4::runTest).collect(Collectors.toList());
	}

	static List<String> runAsyncWithCF(List<Athlete> athletes) {
		List<CompletableFuture<String>> completableFutures = athletes.stream().map(i -> CompletableFuture.supplyAsync(() -> runTest(i))).collect(Collectors.toList());
		return completableFutures.stream().map(CompletableFuture::join).collect(Collectors.toList());
	}

	static List<String> runAsyncWithExecutor(List<Athlete> athletes, Executor executor) {
		List<CompletableFuture<String>> completableFutures = athletes.stream().map(i -> CompletableFuture.supplyAsync(() -> runTest(i), executor))
				.map(future->future.thenCompose(i->CompletableFuture.supplyAsync(()-> CompletableFutureDemo4.runTestTwo(i), executor)))
				.collect(Collectors.toList());
		return completableFutures.stream().map(CompletableFuture::join).collect(Collectors.toList());
	}

	static List<String> runAsyncWithCombine(List<Athlete> athletes, Executor executor) {
		CompletableFuture[] completableFutures = athletes.stream().map(i ->
				CompletableFuture.supplyAsync(() -> runTest(i), executor)
						.thenCombine(CompletableFuture.supplyAsync(() -> CompletableFutureDemo4.runTestTwo(i), executor), (a, b) -> a + b))
				.map(i -> i.thenAccept(log::info)).toArray(CompletableFuture[]::new);
//		CompletableFuture.allOf(completableFutures).join();
		CompletableFuture.anyOf(completableFutures).join();
		return new ArrayList<>();
	}



	static String runTest(Athlete athlete) {
		delay();
		return "我是: " + athlete.getName() + "我的测试成绩是: " + random.nextInt(10) + "s";
	}

	static String runTestTwo(String athlete) {
		delay();
		return athlete;
	}
	static String runTestTwo(Athlete athlete) {
		delay();
		return "我给你" + random.nextInt(100) + "分";
	}

	static void delay() {
		int time = 500 + random.nextInt(2000);
		try {
			Thread.sleep(time);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	public static int[] towSum(int[] nums, int target) {
		Map<Integer, Integer> map = new HashMap<>();
		for (int i = 0; i < nums.length; i++) {
			int tmep = target - nums[i];
			if (map.containsKey(tmep)) {
				return new int[]{i, map.get(tmep)};
			}
			map.put(nums[i], i);
		}
		return null;
	}
}
